import base64
import json
import pickle

from django import http
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from utils import constants
from utils.response_code import RETCODE


class CartsView(View):
    """购物车管理"""
    def get(self, request):
        user = request.user
        if user.is_authenticated:
            # 用户已登录，查询redis购物车
            # 用户已登录，查询redis购物车
            redis_conn = get_redis_connection('carts')
            # 获取redis中的购物车数据
            redis_cart = redis_conn.hgetall('carts_%s' % user.id)
            # 获取redis中的选中状态
            cart_selected = redis_conn.smembers('selected_%s' % user.id)

            # 将redis中的数据构造成跟cookie中的格式一致，方便统一查询
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }
        else:
            # 用户未登录，查询cookies购物车
            # 用户未登录，查询cookies购物车
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                # 将cart_str转成bytes,再将bytes转成base64的bytes,最后将bytes转字典
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

        # 构造购物车渲染数据
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        cart_skus = []
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'count': cart_dict.get(sku.id).get('count'),
                'selected': str(cart_dict.get(sku.id).get('selected')),  # 将True，转'True'，方便json解析
                'default_image_url': sku.default_image,
                'price': str(sku.price),  # 从Decimal('10.2')中取出'10.2'，方便json解析
                'amount': str(sku.price * cart_dict.get(sku.id).get('count')),
            })

        context = {
                'cart_skus': cart_skus,
            }
        return render(request, "cart.html", context)

    def post(self, request):
        # 1 接受参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get("sku_id")  # 商品的id
        count = json_dict.get("count")  # 商品的选定数量
        selected = json_dict.get("selected", True)  # 购物车勾选选项

        # 2 校验
        if not all([sku_id, count]):
            return http.HttpResponseBadRequest("缺少参数")

        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseBadRequest("商品不存在")

        try:
            count = int(count)
        except Exception:
            return http.HttpResponseBadRequest("无效count")

        # 判断selected 是否是布尔值
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseBadRequest("selected无效")

        # 3 判断是否是否登录
        user = request.user
        # 如果用户登录成功,操作redis 购物车
        if user.is_authenticated:
            # # 其次在判断商品库存数量是否足够
            # if sku.stock < count:
            #     return http.JsonResponse({"code": RETCODE.STOCKERR, "errmsg": "商品库存不足"})
            # 01 连接数据库
            redis_conn = get_redis_connection("carts")
            pl = redis_conn.pipeline()  # 多次请求数据，一次返回所有结果
            # 将选定的购物车商品添加到数据库中（redis）
            pl.hincrby("carts_%s" % user.id, sku_id, count)

            if selected:
                pl.sadd("selected_%s" % user.id, sku_id)

            # 执行管道
            pl.execute()
            # 返回响应
            return http.JsonResponse({"code": RETCODE.OK, "errmsg": "添加购物车成功"})
        else:
            # 用户没有登录成功 操作cookie 购物车
            # # 其次在判断商品库存数量是否足够
            # if sku.stock < count:
            #     return http.JsonResponse({"code": RETCODE.STOCKERR, "errmsg": "商品库存不足"})

            cart_str = request.COOKIES.get("carts")  # 购物车
            # 如果用户操作过cookie购物车
            if cart_str:
                # 将cart_str转成bytes,再将bytes转成base64的bytes,最后将bytes转字典
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))

            else:
                # 用户没有操作cookie购物车
                cart_dict = {}

            if sku_id in cart_dict:
                # 累加
                origin_count = cart_dict[sku_id]["count"]
                print(origin_count)
                count += origin_count

            cart_dict[sku_id] = {
                "count":count,
                "selected":selected
            }
            print(cart_dict, "添加到购物车")

            # 将cart_str转成bytes,再将bytes转成base64的bytes,最后将bytes转字典
            cookie_cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 创建响应对象
            response = JsonResponse({'code': RETCODE.OK, 'errmsg': '添加购物车成功'})
            # 响应结果并将购物车数据写入到cookie
            response.set_cookie('carts', cookie_cart_str, max_age=constants.CARTS_COOKIE_EXPIRES)
            return response

    def put(self, request):
        """修改购物车"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')   # 商品id
        count = json_dict.get('count')   # 商品的数量
        selected = json_dict.get('selected', True)  # 勾选项

        # 判断参数是否齐全
        if not all([sku_id, count]):
            return http.HttpResponseBadRequest('缺少必传参数')
        # 判断sku_id是否存在
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseBadRequest('商品sku_id不存在')
        # 判断count是否为数字
        try:
            count = int(count)
        except Exception:
            return http.HttpResponseBadRequest('参数count有误')
        # 判断selected是否为bool值
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseBadRequest('参数selected有误')

        # 判断用户是否登录
        user = request.user
        if user.is_authenticated:
            # 用户已经登录，修改redis购物车数据
            # 1 连接数据库
            redis_conn = get_redis_connection("carts")
            pl = redis_conn.pipeline()
            # 修改既覆盖
            pl.hset("carts_%s" % user.id, sku_id, count)
            # 商品是否被选中
            if selected:
                # true
                # 选中既添加
                pl.sadd("selected_%s" % user.id, sku_id)  # 集合去重复
            else:
                # 未选中表示既不勾选， 去除
                pl.srem("selected_%s" % user.id, sku_id)
            # 执行
            pl.execute()

            # 创建响应对象
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected,
                'name': sku.name,
                'default_image_url': sku.default_image,
                'price': sku.price,
                'amount': sku.price * count,
            }

            return http.JsonResponse({"code": RETCODE.OK, "errmsg": "修改购物车成功", "cart_sku":cart_sku})

        else:
            print("-------else-------")
            # 如果用户未登录，获取cookie购物车
            cart_str = request.COOKIES.get("carts")  # 获取cookie（加密）
            if cart_str:
                # 如果获取到了cookie，解码
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
                print(cart_dict, "用户id{数量， 勾选项}")
            else:
                # 创建一个字典
                cart_dict = {}

        # 因为接口设计为幂等的，直接覆盖
        cart_dict[sku_id] = {
            "count": count,
            "selected": selected,
        }

        # 编码返回cookie
        cookie_str = base64.b64encode(pickle.dumps(cart_dict)).decode()

        # 创建响应对象
        cart_sku = {
            'id': sku_id,
            'count': count,
            'selected': selected,
            'name': sku.name,
            'default_image_url': sku.default_image,
            'price': sku.price,
            'amount': sku.price * count,
        }
        # 返回响应结果
        response = http.JsonResponse({"code": RETCODE.OK, "errmsg": "修改购物车成功", "cart_sku": cart_sku})

        # 设置set_cookie返回到响应头（headers）
        response.set_cookie("carts", cookie_str, max_age=constants.CARTS_COOKIE_EXPIRES)

        return response

    def delete(self, request):
        """删除商品"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')  # 商品id
        print(sku_id)

        # 2 校验
        if not sku_id:
            return http.HttpResponseBadRequest("无效参数")

        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseBadRequest("无效商品")

        # 3 判断用户是否登录了
        user = request.user
        if user.is_authenticated:
            print("--------delete------")
            # 用户已经登录, 删除redis购物车数据
            # 01 连接数据库
            redis_conn = get_redis_connection("carts")
            pl = redis_conn.pipeline()
            pl.hdel("carts_%s" % user.id, sku_id)
            pl.srem("selected_%s" % user.id, sku_id)
            # 执行
            pl.execute()

            return http.JsonResponse({"code": RETCODE.OK, "errmsg": "删除商品成功"})

        else:
            # 用户未登录,删除cookie购物车数据
            carts_str = request.COOKIES.get("carts")
            if carts_str:
                # 解码 最后将bytes转字典
                cart_dict = pickle.loads(base64.b64decode(carts_str.encode()))
                print(cart_dict.keys(), "  22 11")

            else:
                # 创建字典
                cart_dict = {}

            # 创建响应对象
            response = http.JsonResponse({"code": RETCODE.OK, "errmsg": "删除购物车成功"})
            if sku_id in cart_dict:
                del cart_dict[sku_id]  # 删除商品

                # 将字典转成bytes,再将bytes转成base64的bytes,最后将bytes转字符串
                cookie_cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()

                # 将响应结果并将数据库写入set_cookie中
                response.set_cookie("carts", cookie_cart_str, constants.CARTS_COOKIE_EXPIRES)

                return response


class CartSelectedView(View):
    """购物车全选"""
    def put(self, request):
        # 1 接受参数
        json_dict = json.loads(request.body.decode())
        selected = json_dict.get("selected", True)  # 勾选项

       # 2 校验参数
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseBadRequest('参数selected有误')  # 2 判断用户是否登录
        
        user = request.user
        if user.is_authenticated:
            # 用户已经登录,提取redis购物车数据
            # 01 连接数据库
            redis_conn = get_redis_connection("carts")
            cart = redis_conn.hgetall("carts_%s" % user.id)
            # print(cart)
            cartskwargs = cart.keys()   # 得到商品的每一个商品的id
            # print(*cartskwargs)  # 拆包
            if selected:
                # 全选
                redis_conn.sadd("selected_%s" % user.id, *cartskwargs)
            else:
                # 取消全选
                redis_conn.srem("selected_%s" % user.id, *cartskwargs)

            return http.JsonResponse({"code": RETCODE.OK, "errmsg": "全选购物车成功"})
            
        else:
            print("---------else------")
            # 用户未登录, 提取cookie购物车数据
            # 01 取出cookie
            carts_str = request.COOKIES.get("carts")
            if carts_str is not None:
                # 解码，byte转成python中字典
                carts_dict = pickle.loads(base64.b64decode(carts_str.encode()))
                print(carts_dict)
                for sku_id in carts_dict:
                    print(sku_id)
                    carts_dict[sku_id]["selected"] = selected
                    print(carts_dict)
                # 编码，转成byte返回cookie中
                cookie_dict_str = base64.b64encode(pickle.dumps(carts_dict)).decode()
                print(cookie_dict_str)
                response = http.JsonResponse({"code": RETCODE.OK, "errmsg": "购物车全选成功"})
                response.set_cookie("carts", cookie_dict_str, constants.CARTS_COOKIE_EXPIRES)
                return response


class CartsSimpleView(View):
    """展示商品购物车浮窗"""
    def get(self, request):
        # 1 判断用户是否登录
        user = request.user
        if user.is_authenticated:
            # 用户已经登录, 获取redis购物车数据展示
            # 01 连接数据库（redis）
            redis_conn = get_redis_connection("carts")
            # 获取
            redis_cart = redis_conn.hgetall("carts_%s" % user.id)  # 商品
            carts_selected = redis_conn.smembers('selected_%s' % user.id)  # 选项
            print("----------------------登陆的CartsSimple-----------------------")
            print(redis_cart, "redis_cart")
            print(carts_selected, "carts_selected")
            # 将redis中二个数据统一格式
            carts_dict = {}

            for sku_id, count in redis_cart.items():
                carts_dict[int(sku_id)] = {
                    "count": int(count),
                    "selected": sku_id in carts_selected  # 因为selected 存储的也是sku_id，所以比较
                }
            print(carts_dict)
        else:
            print("--------未登录CartsSimpleView---------")
            # 用户未登录,取出cookie中购物车数据
            cookie_carts_str = request.COOKIES.get("carts")
            if cookie_carts_str:
                # 如果取出来了,进行cookie解密在转化成python中的字典
                carts_dict = pickle.loads(base64.b64decode(cookie_carts_str.encode()))
                print(carts_dict)
            else:
                carts_dict = {}

        # 构造购物车数据
        cart_skus = []
        sku_id = carts_dict.keys()  # 取出商品的id
        print(sku_id, "sku_id keys")

        skus = SKU.objects.filter(id__in=sku_id)
        print(skus)

        for sku in skus:
            cart_skus.append({
                "id": sku.id,
                "name": sku.name,
                # "price": sku.price,
                "count": carts_dict[sku.id]["count"],
                # "select": carts_dict.get(sku.id).get("selected"),
                "default_image_url": sku.default_image
            })

        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "ok", "cart_skus": cart_skus})








